using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using OpenComposite.Repository.Properties;
using System.Web.Services.Discovery;
using System.Net;
using System.Collections;
using System.Web.Services.Description;
using System.Xml;
using System.IO;
using System.Xml.Schema;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.Runtime.Serialization;
using System.CodeDom;
using System.Reflection;
using System.Xml.Serialization;

namespace OpenComposite.EII.RepositoryUIs
{
	public partial class FormCreateNewAPIService : Forms.FormCreateNewBase
	{
		#region Initialization
		public FormCreateNewAPIService(Repository.WebService webService, int idRepository, bool bAllowContinue)
			: base(webService, webService, bAllowContinue)
		{
			InitializeComponent();

			_idRepository = idRepository;

			init();
		}
		private void init()
		{
			_webmethods = new List<OpenComposite.EII.Repository.WebMethod>();

			dgvWebMethods.AutoGenerateColumns = false;
			dgvWebMethods.DataSource = new BindingList<Repository.WebMethod>(_webmethods);

			this.DialogResult = DialogResult.Cancel;
		}
		#endregion

		#region Variables
		private int _idRepository = -1;

		private List<Repository.WebMethod> _webmethods;
		private string _apiFileName = null;
		private string _apiFilePath = null;

		private System.Web.Services.Description.ServiceDescription _wsdl = null;
		#endregion

		#region Methods

		protected override void OnSaveClose(CancelEventArgs e)
		{
			if ( save() ) {
				base.OnSaveClose(e);
			} else {
				e.Cancel = true;
			}
		}
		protected override void OnSaveContinue(CancelEventArgs e)
		{
			if ( save() ) {
				base.OnSaveContinue(e);
			} else {
				e.Cancel = true;
			}
		}
		protected override void OnCancel()
		{
			foreach ( Repository.WebMethod meth in _webmethods ) {
				meth.DeleteFromDBInternal(false);
			}
			base.OnCancel();
		}
		private bool save()
		{
			bool ok = false;

			ok = saveWebService();
			if ( ok )
				ok = saveWebMethods();

			return ok;
		}
		private bool saveWebService()
		{
			Repository.WebService ws = this.RepositoryItem as Repository.WebService;
			if ( ws == null )
				return false;
			else {
				ws.DomainId = this.DomainID;
				return ws.Save();
			}
		}
		private bool saveWebMethods()
		{
			Repository.WebService ws = this.RepositoryItem as Repository.WebService;
			if ( ws == null )
				return false;

			bool ok = false;
			foreach ( Repository.WebMethod meth in _webmethods ) {
				meth.DomainId = this.DomainID;
				ok = meth.Save();
				if ( ok )
					Global.Data.AddRepositoryHierarchy(ws, meth, _idRepository);
				else
					continue;
			}
			return ok;
		}

		private void browseForAPI()
		{
			browseForAPI(false);
		}

		private void browseForAPI(bool update)
		{
			Repository.WebService ws = this.RepositoryItem as Repository.WebService;
			RepositoryService repSvc = this.RepositoryService;
			if ( ws == null )
				throw new Exception("Repository Item is not a web service.");
			if ( repSvc == null )
				throw new NullReferenceException("RepositoryService not available.");

			if ( !update ) {
				OpenFileDialog openDlg = new OpenFileDialog();

				openDlg.AddExtension = true;
				openDlg.CheckFileExists = true;
				openDlg.CheckPathExists = true;
				openDlg.DefaultExt = "dll";
				openDlg.Filter = "Dynamic Link Library (*.dll)|*.dll";
				openDlg.Multiselect = false;
				openDlg.Title = "Browse for API Service file";

				if ( openDlg.ShowDialog() == DialogResult.OK ) {
					_apiFilePath = openDlg.FileName;
					_apiFileName = Path.GetFileName(openDlg.FileName);
					txtWSUrl.Text = openDlg.FileName;
				}
			}

			if ( txtWSUrl.Text != null && txtWSUrl.Text != "" ) {

				_wsdl = null;

				// generate contract code
				Assembly apiAssembly = null;
				apiAssembly = Assembly.LoadFile(_apiFilePath);
				string codestrContract = createAssemblyImage(apiAssembly);

				codestrContract =
					codestrContract.Substring(0, codestrContract.LastIndexOf("|"));

				List<MethodInfo> methods = new List<MethodInfo>();

				try {
					using ( FormSelectAPIMethods frmApiMeth = new FormSelectAPIMethods(apiAssembly) ) {
						if ( frmApiMeth.ShowDialog(this) == DialogResult.OK )
							methods = frmApiMeth.SelectedMethods;
					}
				} catch ( ReflectionTypeLoadException ) {
					// e.g. referenced assemblies not found
					MessageBox.Show("Error loading assembly");
					return;
				}

				// save metadata
				string strMetaData = "";

				// set webservice values
				ws.Name = apiAssembly.GetName().Name;
				ws.Uri = _apiFileName;
				ws.Namespace = apiAssembly.GetName().Name;
				ws.Description = apiAssembly.GetName().FullName.Replace(", ", Environment.NewLine);
				ws.ContractCSharpCode = codestrContract;
				ws.MetaData = strMetaData;
				//	ws.InterfaceFullName = typeRef.BaseType;

				ws.ClientFullName = apiAssembly.GetName().FullName;

				// get webmethods (operations)
				dgvWebMethods.DataSource = null;
				_webmethods.Clear();

				#region OLD: webmethods
				//foreach (PortType porttype in _wsdl.PortTypes) {
				//    foreach (Operation op in porttype.Operations) {
				//        bool bSC;
				//        Repository.WebMethod meth = repSvc.GetItem(
				//            OpenComposite.EII.Repository.ItemType.WebMethod, true, _idRepository, false, false, out bSC)
				//            as Repository.WebMethod;
				//        meth.Name = op.Name;
				//        meth.Description = op.Documentation;
				//        meth.PortType = op.PortType.Name;
				//        meth.WebServiceID = ws.ID;
				//        meth.Action = findAction(op);

				//        System.ServiceModel.Description.OperationDescription wsop = cdesc.Operations.Find(meth.Name);
				//        System.ServiceModel.Description.MessageDescription mdIn = null, mdOut = null;
				//        foreach (System.ServiceModel.Description.MessageDescription md in wsop.Messages) {
				//            if (md.Direction == System.ServiceModel.Description.MessageDirection.Input)
				//                mdIn = md;
				//            else if (md.Direction == System.ServiceModel.Description.MessageDirection.Output)
				//                mdOut = md;
				//        }
				//        System.Reflection.FieldInfo baseType = null;
				//        if (mdIn != null && mdIn.Body != null && mdIn.Body.Parts.Count > 0) {
				//            string typenames = "", varnames = "";
				//            foreach (MessagePartDescription part in mdIn.Body.Parts) {
				//                baseType = part.GetType().GetField("baseType", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
				//                if (typenames != "") typenames += ";";
				//                if (varnames != "") varnames += ";";
				//                object typeobj = baseType.GetValue(part);
				//                string typenm = null;
				//                if (typeobj != null) {
				//                    typenm = typeobj.ToString();
				//                    foreach (XmlQualifiedName xqn in xsdSet.GlobalTypes.Names) {
				//                        if (xqn.Name == typenm) {
				//                            typenm = xqn.ToString();
				//                            break;
				//                        }
				//                    }
				//                }
				//                if (typenm != null)
				//                    typenames += typenm;
				//                else
				//                    typenames += part.Name;
				//                varnames += part.Name;
				//            }
				//            meth.InputWrapperName = string.Format("{0}:{1}", mdIn.Body.WrapperNamespace, mdIn.Body.WrapperName);
				//            meth.InputTypeName = typenames;
				//            meth.InputVariableName = varnames;
				//        }
				//        if (op.Messages.Input != null) {
				//            meth.InputSchema = getMessageSchema(op.Messages.Input.Message); //getSchemaFromMessage(op.Messages.Input.Message);
				//            meth.InputAction = op.Messages.Input.Message.ToString();
				//        }
				//        if (mdOut != null && mdOut.Body != null) {
				//            string typenames = "", varnames = "";
				//            if (mdOut.Body.Parts.Count > 0) {
				//                foreach (MessagePartDescription part in mdOut.Body.Parts) {
				//                    baseType = part.GetType().GetField("baseType", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
				//                    if (typenames != "") typenames += ";";
				//                    if (varnames != "") varnames += ";";
				//                    object typeobj = baseType.GetValue(part);
				//                    string typenm = null;
				//                    if (typeobj != null) {
				//                        typenm = typeobj.ToString();
				//                        foreach (XmlQualifiedName xqn in xsdSet.GlobalTypes.Names) {
				//                            if (xqn.Name == typenm) {
				//                                typenm = xqn.ToString();
				//                                break;
				//                            }
				//                        }
				//                    }
				//                    if (typenm != null)
				//                        typenames += typenm;
				//                    else
				//                        typenames += part.Name;
				//                    varnames += part.Name;
				//                }
				//            }
				//            if (mdOut.Body.ReturnValue != null) {
				//                MessagePartDescription part = mdOut.Body.ReturnValue;
				//                baseType = part.GetType().GetField("baseType", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
				//                if (typenames != "") typenames += ";";
				//                if (varnames != "") varnames += ";";
				//                object typeobj = baseType.GetValue(part);
				//                string typenm = null;
				//                if (typeobj != null) {
				//                    typenm = typeobj.ToString();
				//                    foreach (XmlQualifiedName xqn in xsdSet.GlobalTypes.Names) {
				//                        if (xqn.Name == typenm) {
				//                            typenm = xqn.ToString();
				//                            break;
				//                        }
				//                    }
				//                }
				//                if (typenm != null)
				//                    typenames += typenm;
				//                else
				//                    typenames += part.Name;
				//                varnames += part.Name;
				//            }
				//            meth.OutputWrapperName = string.Format("{0}:{1}", mdOut.Body.WrapperNamespace, mdOut.Body.WrapperName);
				//            meth.OutputTypeName = typenames;
				//            meth.OutputVariableName = varnames;
				//        }
				//        if (op.Messages.Output != null) {
				//            meth.OutputSchema = getMessageSchema(op.Messages.Output.Message);//getSchemaFromMessage(op.Messages.Output.Message);
				//            meth.OutputAction = op.Messages.Output.Message.ToString();
				//        }

				//        _webmethods.Add(meth);
				//    }
				//} 
				#endregion

				foreach ( MethodInfo method in methods ) {
					string inputschema = null;
					string outputschema = null;
					string inputwrapper = "";
					string inputvars = "";
					string inputtypes = "";
					string outputwrapper = "";
					string outputvars = "";
					string outputtypes = "";

					int inCount = 0;
					int outCount = 0;

					if ( method.IsPublic ) {

						XmlSchemas xsdsInput = new XmlSchemas();
						XmlSchema xsdInput = new XmlSchema();
						XmlSchemas xsdsOutput = new XmlSchemas();
						XmlSchema xsdOutput = new XmlSchema();
						XmlSchemaExporter xseInput = new XmlSchemaExporter(xsdsInput);
						XmlSchemaExporter xseOutput = new XmlSchemaExporter(xsdsOutput);
						SoapReflectionImporter sriInput = new SoapReflectionImporter();
						SoapReflectionImporter sriOutput = new SoapReflectionImporter();
						XmlTypeMapping xtm = null;
						XmlSchema xsd2 = new XmlSchema();

						XmlWriterSettings xws = new XmlWriterSettings();
						xws.OmitXmlDeclaration = true;

						foreach ( ParameterInfo param in method.GetParameters() ) {
							if ( param.IsOut ) {
								Type t = Type.GetType(param.ParameterType.FullName.Replace("&", ""));
								if ( t != null )
									xtm = sriOutput.ImportTypeMapping(t);
								else
									throw new ArgumentException(string.Format("Unknown reference type {0} cannot be serialized.", param.ParameterType.FullName), param.Name);

								xseOutput.ExportTypeMapping(xtm);
								outCount++;
								outputvars += param.Name + ";";
								outputtypes += param.ParameterType.FullName.Replace("&", "") + ";";
							} else {
								xtm = sriInput.ImportTypeMapping(param.ParameterType);
								inputvars += param.Name + ";";
								inputtypes += param.ParameterType.FullName + ";";
								xseInput.ExportTypeMapping(xtm);
							}
							inCount++;
						}

						XmlSchemaElement xseWrapper = new XmlSchemaElement();
						xseWrapper.Name = inputwrapper;
						XmlSchemaComplexType xsdComplexType = new XmlSchemaComplexType();
						xseWrapper.SchemaType = xsdComplexType;
						XmlSchemaSequence xsdSeq = new XmlSchemaSequence();
						xsdComplexType.Particle = xsdSeq;

						bool bSC;
						Repository.WebMethod meth = repSvc.GetItem(
							OpenComposite.EII.Repository.ItemType.WebMethod, true, _idRepository, false, false, out bSC)
							as Repository.WebMethod;
						meth.Name = method.Name;
						meth.Action = method.ToString();
						//meth.PortType = op.PortType.Name;
						meth.WebServiceID = ws.ID;

						#region Input
						if ( inCount > 0 ) {
							inputvars = inputvars.Substring(0, inputvars.LastIndexOf(';'));
							inputtypes = inputtypes.Substring(0, inputtypes.LastIndexOf(';'));
							inputwrapper = method.Name + "Request";

							if ( inCount >= 1 ) {
								foreach ( XmlSchema xsd in xsdsInput )
									foreach ( XmlSchemaObject xso in xsd.Items )
										if ( xso is XmlSchemaElement )
											xsdSeq.Items.Add(xso);
										else if ( xsd2.Items.Contains(xso) == false )
											xsd2.Items.Add(xso);

								xsd2.Items.Add(xseWrapper);
							}

							xsdInput = xsd2;

							using ( MemoryStream ms = new MemoryStream() )
							using ( XmlWriter xw = XmlWriter.Create(ms, xws) ) {
								xsd2.Write(xw);
								xw.Flush();

								ms.Position = 0;
								StreamReader sr = new StreamReader(ms);
								inputschema = sr.ReadToEnd();
							}

							//xsdInput.Namespaces.Add("", "http://www.theopencomposite.com/canonical_document");
							//xsdInput.TargetNamespace = "http://www.theopencomposite.com/canonical_document";
							xsdInput.Namespaces.Add("", method.ReflectedType.Namespace);
							xsdInput.TargetNamespace = method.ReflectedType.Namespace;
							xsdInput.ElementFormDefault = XmlSchemaForm.Qualified;
							xsdInput.AttributeFormDefault = XmlSchemaForm.Unqualified;

							meth.InputSchema = xsdInput;
							meth.InputTypeName = inputtypes;
							meth.InputVariableName = inputvars;
							meth.InputWrapperName = inputwrapper;

						}

						#endregion

						#region Output
						if ( method.ReturnType != typeof(void) || outCount > 0 ) {
							xsd2 = new XmlSchema();

							xtm = sriOutput.ImportTypeMapping(method.ReturnType);
							xseOutput.ExportTypeMapping(xtm);
							outputvars += "returnValue";
							outputtypes += method.ReturnType.FullName;
							outputwrapper = method.Name + "Response";
							outCount++;

							if ( outCount >= 1 ) {
								xseWrapper = new XmlSchemaElement();
								xseWrapper.Name = outputwrapper;
								xsdComplexType = new XmlSchemaComplexType();
								xseWrapper.SchemaType = xsdComplexType;
								xsdSeq = new XmlSchemaSequence();
								xsdComplexType.Particle = xsdSeq;

								foreach ( XmlSchema xsd in xsdsOutput )
									foreach ( XmlSchemaObject xso in xsd.Items )
										if ( xso is XmlSchemaElement )
											xsdSeq.Items.Add(xso);
										else if ( xsd2.Items.Contains(xso) == false )
											xsd2.Items.Add(xso);

								xsd2.Items.Add(xseWrapper);
							}

							xsdOutput = xsd2;

							using ( MemoryStream ms = new MemoryStream() )
							using ( XmlWriter xw = XmlWriter.Create(ms, xws) ) {
								xsd2.Write(xw);
								xw.Flush();

								ms.Position = 0;
								StreamReader sr = new StreamReader(ms);
								outputschema = sr.ReadToEnd();
							}

							if ( outputvars[outputvars.Length - 1] == ';' )
								outputvars = outputvars.Substring(outputvars.Length - 1, 1);
							if ( outputtypes[outputtypes.Length - 1] == ';' )
								outputtypes = outputtypes.Substring(outputtypes.Length - 1, 1);

							//xsdOutput.Namespaces.Add("", "http://www.theopencomposite.com/canonical_document");
							//xsdOutput.TargetNamespace = "http://www.theopencomposite.com/canonical_document";
							xsdInput.Namespaces.Add("", method.ReflectedType.Namespace);
							xsdOutput.TargetNamespace = method.ReflectedType.Namespace;
							xsdOutput.ElementFormDefault = XmlSchemaForm.Qualified;
							xsdOutput.AttributeFormDefault = XmlSchemaForm.Unqualified;

							meth.OutputSchema = xsdOutput;
							meth.OutputTypeName = outputtypes;
							meth.OutputVariableName = outputvars;
							meth.OutputWrapperName = outputwrapper;
						}
						#endregion

						_webmethods.Add(meth);
					}
				}
			}
		}

		private string createAssemblyImage(Assembly apiAssembly)
		{
			StringBuilder[] assemblyImage = new StringBuilder[apiAssembly.GetFiles().Length];
			int i = 0;
			foreach ( FileStream fs in apiAssembly.GetFiles(true) ) {
				byte[] bytes = new byte[fs.Length];
				fs.Read(bytes, 0, (int)fs.Length);
				assemblyImage[i] = new StringBuilder();
				foreach ( byte data in bytes ) {
					assemblyImage[i].Append(data.ToString()).Append(",");
				}
				i++;
			}

			string codestrContract = null;
			foreach ( StringBuilder image in assemblyImage ) {
				codestrContract += image.ToString().Substring(0, image.ToString().LastIndexOf(',')) + "|";
			}

			return codestrContract;
		}

		private string findAction(System.Web.Services.Description.Operation op)
		{
			string action = "";
			foreach ( System.Web.Services.Description.Binding binding in _wsdl.Bindings ) {
				if ( binding.Type.Name == op.PortType.Name ) {
					foreach ( OperationBinding opBinding in binding.Operations ) {
						if ( opBinding.Name == op.Name ) {
							foreach ( object extObj in opBinding.Extensions ) {
								SoapOperationBinding soapBind = extObj as SoapOperationBinding;
								Soap12OperationBinding soap12Bind = extObj as Soap12OperationBinding;
								if ( soapBind != null ) {
									action = soapBind.SoapAction;
									goto End;
								} else if ( soap12Bind != null ) {
									action = soap12Bind.SoapAction;
									goto End;
								}
							}
						}
					}
				}
			}
End:
			return action;
		}

		private XmlSchema getMessageSchema(XmlQualifiedName msgname)
		{
			//get Message from WSDL Document
			System.Web.Services.Description.Message msg = _wsdl.Messages[msgname.Name];

			//create new Schema Builder for assembling the Message Schema
			XmlSchema xsdResult = new XmlSchema();
			xsdResult.ElementFormDefault = XmlSchemaForm.Qualified;

			List<string> lstAddedNS = new List<string>();

			//add WSDL Document Namespaces to the Schema Builder
			int i = 0;
			foreach ( XmlSchema xsd in _wsdl.Types.Schemas ) {
				if ( !string.IsNullOrEmpty(xsd.TargetNamespace) && !lstAddedNS.Contains(xsd.TargetNamespace) ) {
					xsdResult.Namespaces.Add(string.Format("q{0}", i), xsd.TargetNamespace);
					lstAddedNS.Add(xsd.TargetNamespace);
					i++;
				}
			}

			foreach ( MessagePart messagePart in msg.Parts ) {
				XmlSchemaElement xse =
					_wsdl.Types.Schemas.Find(messagePart.Element, typeof(System.Xml.Schema.XmlSchemaElement))
						as XmlSchemaElement;
				if ( xse != null ) {
					xsdResult.TargetNamespace = xse.QualifiedName.Namespace;
					xsdResult.Items.Add(xse);
				}
			}
			return xsdResult;
		}
		private void showInformations()
		{
			Repository.WebService ws = this.RepositoryItem as Repository.WebService;
			if ( ws == null )
				throw new Exception("Repository Item is not a webservice.");

			this.SuspendLayout();
			try {
				if ( ws != null ) {
					txtName.Text = ws.Name;
					txtDesc.Text = ws.Description;
					txtXmlns.Text = ws.Namespace;
				} else {
					txtName.Text = "- Not Available -";
					txtDesc.Text = "";
					txtXmlns.Text = "";
				}
				dgvWebMethods.DataSource = null;
				dgvWebMethods.Rows.Clear();
				dgvWebMethods.DataSource = _webmethods;
			} finally {
				this.ResumeLayout(true);
			}

		}

		private XmlSchema getSchema(XmlQualifiedName message,
									DiscoveryClientProtocol client,
									System.Web.Services.Description.ServiceDescription wsdl)
		{
			XmlSchemaSet schemaset = new XmlSchemaSet();
			XmlSchema xsd = null;
			XmlSchemaObject xsdObj = null;
			System.Web.Services.Description.Message msg = wsdl.Messages[message.Name];
			MessagePart part = msg.Parts[0];
			// search in wsdl types
			//wsdl.Types.Schemas.Compile(null, true);
			XmlSchemaElement xsdElement = (XmlSchemaElement)wsdl.Types.Schemas.Find(
				part.Element, typeof(XmlSchemaElement));

			if ( xsdElement != null ) {
				xsdObj = xsdElement;
			} else {
				// search imported documents
				foreach ( XmlSchema schema in wsdl.Types.Schemas ) {
					schemaset.Add(schema);
				}
				schemaset.Compile();

				xsdObj = schemaset.GlobalElements[part.Element];
			}
			if ( xsdObj != null ) {
				xsd = new XmlSchema();
				xsd.Items.Add(xsdObj);
				schemaset.Add(xsd);
				schemaset.Compile();
			}

			start(xsd);

			XmlWriterSettings settings = new XmlWriterSettings();
			settings.Indent = false;
			settings.OmitXmlDeclaration = true;
			settings.ConformanceLevel = ConformanceLevel.Auto;
			using ( StringWriter sw = new StringWriter() )
			using ( XmlWriter xw = XmlWriter.Create(sw, settings) ) {
				xsd.Write(xw, new XmlNamespaceManager(schemaset.NameTable));
				xw.Flush();
				string sXSD = sw.ToString();
			}
			return xsd;
		}
		private void start(XmlSchema schema)
		{
			foreach ( XmlSchemaType type in schema.SchemaTypes.Values ) {
				if ( type is XmlSchemaComplexType ) {
					XmlSchemaComplexType ct = type as XmlSchemaComplexType;
					walkTheParticle(ct.ContentTypeParticle);
				}
			}
			foreach ( XmlSchemaElement el in schema.Elements.Values ) {
				walkTheParticle(el);
			}
			foreach ( XmlSchemaAnnotated xsa in schema.Items ) {
				if ( xsa is XmlSchemaGroup ) {
					XmlSchemaGroup xsg = xsa as XmlSchemaGroup;
					walkTheParticle(xsg.Particle);
				}
			}
		}

		private XmlSchema getSchemaFromMessage(XmlQualifiedName msgname)
		{
			//get Message from WSDL Document
			System.Web.Services.Description.Message msg = _wsdl.Messages[msgname.Name];

			//create new Schema Builder for assembling the Message Schema
			XmlSchema xsdResult = new XmlSchema();
			xsdResult.ElementFormDefault = XmlSchemaForm.Qualified;

			List<string> lstAddedNS = new List<string>();
			XmlSchemaSet xsdSet = new XmlSchemaSet();

			//add WSDL Document Namespaces to the Schema Builder
			int i = 0;
			foreach ( XmlSchema xsd in _wsdl.Types.Schemas ) {
				//if ( !xsdSet.Contains(xsd.TargetNamespace) ) {
				//    xsdSet.Add(xsd);
				//    xsdSet.Compile();
				//}
				if ( !lstAddedNS.Contains(xsd.TargetNamespace) ) {
					xsdResult.Namespaces.Add(string.Format("q{0}", i), xsd.TargetNamespace);
					lstAddedNS.Add(xsd.TargetNamespace);
				}
				i++;
			}

			xsdSet.Compile();
			foreach ( XmlSchema xsd in xsdSet.Schemas() ) {
				//if ( !_wsdl.Types.Schemas.Contains(xsd.TargetNamespace) ) {
				//    _wsdl.Types.Schemas.Add(xsd);
				//}
				if ( !lstAddedNS.Contains(xsd.TargetNamespace) ) {
					xsdResult.Namespaces.Add(string.Format("q{0}", i), xsd.TargetNamespace);
					lstAddedNS.Add(xsd.TargetNamespace);
				}
				i++;
			}
			_wsdl.Types.Schemas.Compile(null, true);

			#region process Messages Parts
			foreach ( MessagePart messagePart in msg.Parts ) {
				XmlSchemaElement xse =
					_wsdl.Types.Schemas.Find(messagePart.Element, typeof(System.Xml.Schema.XmlSchemaElement))
						as XmlSchemaElement;
				if ( xse != null ) {
					xsdResult.Items.Add(xse);
					continue;
				}
				if ( messagePart.Type.IsEmpty == false ) {
					//add Type Definition of the Message Part to the Schema Builder
					this.addSchemaTypeToSchema(messagePart.Type, xsdResult);

					xsdResult.TargetNamespace = messagePart.Type.Namespace;
				}

				if ( messagePart.Element.IsEmpty == false ) {
					//get Element from WSDL
					XmlSchemaObject msgPartObject =
						this.getSchemaObjectFromQName(messagePart.Element, true);

					xsdResult.TargetNamespace = messagePart.Element.Namespace;

					if ( msgPartObject is XmlSchemaElement ) {
						//add Element to the Schema Builder
						this.addSchemaElementToSchema((XmlSchemaElement)msgPartObject, xsdResult, false);
					}

				}

				if ( messagePart.Type.IsEmpty == false ) {
					//create new Element representing the MessagePart Name
					XmlSchemaElement schemaElement = new XmlSchemaElement();
					schemaElement.Name = messagePart.Name;
					schemaElement.SchemaTypeName = messagePart.Type;
					xsdResult.Items.Add(schemaElement);
				}
			}
			#endregion

			//compile Message Schema
			//this.checkXmlSchema(xsdResult);

			//return Content of the built Message Schema
			return xsdResult;
		}
		private void processXmlSchemaParticle(XmlSchema xsdResult, XmlSchemaParticle part)
		{
			//<xs: element ... />
			if ( part is XmlSchemaElement ) {
				if ( ( (XmlSchemaElement)part ).SchemaTypeName.IsEmpty == false ) {
					this.addSchemaTypeToSchema(( (XmlSchemaElement)part ).SchemaTypeName, xsdResult);
				}
				if ( ( (XmlSchemaElement)part ).SchemaType is XmlSchemaComplexType ) {
					XmlSchemaComplexType ct = ( (XmlSchemaElement)part ).SchemaType as XmlSchemaComplexType;
					if ( ct.ContentTypeParticle is XmlSchemaSequence ) {
						//get Child Sequence from Complex Type
						XmlSchemaSequence seq = (XmlSchemaSequence)ct.ContentTypeParticle;

						#region process Elements of the Sequence
						foreach ( XmlSchemaParticle partCT in seq.Items ) {
							processXmlSchemaParticle(xsdResult, partCT);
						}
						#endregion
					} else if ( ct.ContentTypeParticle is XmlSchemaChoice ) {
						//get Child Choice from Complex Type
						XmlSchemaChoice choice = (XmlSchemaChoice)ct.ContentTypeParticle;
						foreach ( XmlSchemaParticle partCT in choice.Items ) {
							processXmlSchemaParticle(xsdResult, partCT);
						}
					}
				}

				if ( ( (XmlSchemaElement)part ).RefName.IsEmpty == false ) {
					XmlSchemaElement refElement = (XmlSchemaElement)
						this.getSchemaObjectFromQName(( (XmlSchemaElement)part ).RefName,
						true);
					refElement.Namespaces.Add("", refElement.QualifiedName.Namespace);
					this.addSchemaElementToSchema(refElement, xsdResult, false);
				}
			}

			//<xs:any namespace='a_namespace' />
			if ( part is XmlSchemaAny ) {
				if ( _wsdl.Types.Schemas[( (XmlSchemaAny)part ).Namespace] != null ) {
					XmlSchema anyRefSchema = _wsdl.Types.Schemas[( (XmlSchemaAny)part ).Namespace];

					foreach ( XmlSchemaObject anyObj in anyRefSchema.Items ) {
						xsdResult.Items.Add(anyObj);
					}
					if ( xsdResult.TargetNamespace == null || xsdResult.TargetNamespace == string.Empty ) {
						xsdResult.TargetNamespace = anyRefSchema.TargetNamespace;
					}
				}
			}
		}
		private bool addSchemaTypeToSchema
			(XmlQualifiedName typename, XmlSchema xsdResult)
		{
			XmlSchemaType schemaType = this.getSchemaTypeFromType(typename);
			if ( schemaType == null )
				return false;

			if ( schemaType is XmlSchemaComplexType ) {
				if ( ( (XmlSchemaComplexType)schemaType ).ContentTypeParticle is XmlSchemaSequence ) {
					XmlSchemaSequence seq = (XmlSchemaSequence)
						( (XmlSchemaComplexType)schemaType ).ContentTypeParticle;
					foreach ( XmlSchemaObject item in seq.Items ) {
						if ( item is XmlSchemaElement ) {
							if ( ( (XmlSchemaElement)item ).QualifiedName != typename ) {
								//check if Element already exists in Schema
								bool elementAlreadyAdded = this.checkSchemaObjectExists(
									( (XmlSchemaElement)item ).QualifiedName, xsdResult);
								//process Element
								this.addSchemaElementToSchema((XmlSchemaElement)item,
									xsdResult, true);
							}
						}
						if ( item is XmlSchemaType ) {
							this.addSchemaTypeToSchema(
							  ( (XmlSchemaType)item ).QualifiedName, xsdResult);
						}
					}
				}
			}
			if ( xsdResult.TargetNamespace == null
				| xsdResult.TargetNamespace == string.Empty ) {
				if ( schemaType is XmlSchemaType ) {
					xsdResult.TargetNamespace =
						( (XmlSchemaType)schemaType ).QualifiedName.Namespace;
				}
			}
			if ( xsdResult.Items.Contains(schemaType) == false ) {
				xsdResult.Items.Add(schemaType);
			}

			return true;
		}
		/// <summary>
		/// Adds Element that is specified by ElementName to the SchemaBuilder
		/// </summary>
		/// <param name="Element">Xml Element that is to add</param>
		/// <param name="SchemaBuilder"></param>
		/// <param name="ReadOnly">Flag that determines, whether the collected Elements 
		/// Information have to be written into the SchemaBuilder or not. Important for processing
		/// nested Elements</param>
		private void addSchemaElementToSchema
			(XmlSchemaElement element, XmlSchema xsdResult, bool readOnly)
		{

			//process Element's Type
			if ( element.SchemaTypeName.IsEmpty == false ) {
				this.addSchemaTypeToSchema(element.SchemaTypeName, xsdResult);
			}
			//process Element's Reference
			if ( element.RefName.IsEmpty == false ) {
				XmlSchemaElement refElement = (XmlSchemaElement)
					this.getSchemaObjectFromQName(element.RefName, true);
			}


			#region get nested Element Content

			if ( !( element.ElementSchemaType is XmlSchemaComplexType ) ) {
				//process Simple Type
				if ( element.ElementSchemaType is XmlSchemaSimpleType ) {
					if ( !this.addSchemaTypeToSchema(element.SchemaTypeName, xsdResult) &&
						 element.Parent is XmlSchema )
						xsdResult.Items.Add(element);
				}
				return;
			}

			//process Complex Type
			XmlSchemaComplexType complType = (XmlSchemaComplexType)element.ElementSchemaType;

			//assign Complex Type to Element of Interest
			//			schemaElement.SchemaType = complType;

			//if Child is Sequence
			if ( complType.ContentTypeParticle is XmlSchemaSequence ) {
				//get Child Sequence from Complex Type
				XmlSchemaSequence seq = (XmlSchemaSequence)complType.ContentTypeParticle;

				#region process Elements of the Sequence
				foreach ( XmlSchemaParticle part in seq.Items ) {
					processXmlSchemaParticle(xsdResult, part);
				}
				#endregion
			} else if ( complType.ContentTypeParticle is XmlSchemaChoice ) {
				//get Child Choice from Complex Type
				XmlSchemaChoice choice = (XmlSchemaChoice)complType.ContentTypeParticle;
				foreach ( XmlSchemaParticle part in choice.Items ) {
					processXmlSchemaParticle(xsdResult, part);
				}
			}
			#endregion


			if ( readOnly == false ) {
				//add Element to Schema Builder
				if ( xsdResult.Items.Contains(element) == false ) {
					element.Namespaces.Add("tns", element.QualifiedName.Namespace);
					xsdResult.Items.Add(element);
				}
			}
		}
		private XmlSchemaObject getSchemaObjectFromQName
			(XmlQualifiedName QName, bool ObjectIsElement)
		{
			XmlSchema schema = _wsdl.Types.Schemas[QName.Namespace];
			//schema can be null for simple Type Namespaces
			if ( schema == null ) {
				return null;
			}

			foreach ( XmlSchemaObject sObj in schema.Items ) {
				if ( sObj.GetType().GetProperty("QualifiedName") == null ) {
					continue;
				}
				if ( (XmlQualifiedName)( sObj.GetType().GetProperty("QualifiedName")
					.GetValue(sObj, null) ) == QName
					&&
					( ObjectIsElement == true ? ( sObj is XmlSchemaElement ) : !( sObj is XmlSchemaElement ) ) ) {
					return sObj;
				}
			}

			return null;
		}
		private XmlSchemaType getSchemaTypeFromType(XmlQualifiedName typeName)
		{
			return (XmlSchemaType)this.getSchemaObjectFromQName(typeName, false);
		}
		private bool checkSchemaObjectExists(XmlQualifiedName QName, XmlSchema schema)
		{
			foreach ( XmlSchemaObject sObj in schema.Items ) {
				if ( sObj.GetType().GetProperty("QualifiedName") != null ) {
					if ( (XmlQualifiedName)sObj.GetType().GetProperty("QualifiedName")
							.GetValue(sObj, null) == QName ) {
						return true;
					}
				}
			}
			return false;
		}
		private void checkXmlSchema(XmlSchema schema)
		{
			//20050509
			//string schemaContentString = PEPExplorer.GetXmlSchemaContent(XmlSchema);
			//System.IO.MemoryStream memStream = new System.IO.MemoryStream();
			//byte[] schemaContentData =
			//    System.Text.Encoding.ASCII.GetBytes(schemaContentString);
			//memStream.Write(schemaContentData, 0, schemaContentData.Length);
			//memStream.Position = 0;
			//XmlSchema dummySchema = XmlSchema.Read(memStream,
			//    new ValidationEventHandler(XmlValEventHandler));

			XmlSchemaSet xsdset = new XmlSchemaSet();
			xsdset.XmlResolver = null;
			xsdset.Add(schema);
			xsdset.Compile();

			return;
		}

		private void walkTheParticle(XmlSchemaParticle particle)
		{
			if ( particle is XmlSchemaElement ) {
				XmlSchemaElement elem = particle as XmlSchemaElement;

				// todo: insert your processing code here

				if ( elem.RefName.IsEmpty ) {
					XmlSchemaType type = (XmlSchemaType)elem.ElementSchemaType;
					if ( type is XmlSchemaComplexType ) {
						XmlSchemaComplexType ct = type as XmlSchemaComplexType;
						if ( ct.QualifiedName.IsEmpty ) {
							walkTheParticle(ct.ContentTypeParticle);
						} else {
							elem.SchemaType = ct;
							elem.SchemaTypeName = XmlQualifiedName.Empty;
							walkTheParticle(ct.ContentTypeParticle);
						}
					}
				}
			} else if ( particle is XmlSchemaGroupBase ) {
				//xs:all, xs:choice, xs:sequence
				XmlSchemaGroupBase baseParticle = particle as XmlSchemaGroupBase;
				foreach ( XmlSchemaParticle subParticle in baseParticle.Items ) {
					walkTheParticle(subParticle);
				}
			}
		}

		private void showXmlString(string xml)
		{
			XmlDocument xd = new XmlDocument();
			formXmlViewer frm = new formXmlViewer();
			xd.LoadXml(xml);
			frm.XmlDocument = xd;
			frm.ShowDialog();
		}

		//private System.Web.Services.Description.ServiceDescription requestWSDLFromSoapService(Uri uri)
		//{
		//    System.Web.Services.Description.ServiceDescription sdesc = null;

		//    try {
		//        SoapWsdlProxy wp = new SoapWsdlProxy(uri);
		//        WSE2.SoapEnvelope se = wp.RequestDescription();

		//        if ( se != null && se.Body != null && se.Body.FirstChild != null ) {
		//            using( MemoryStream ms = new MemoryStream() )
		//            using ( XmlWriter xw = XmlWriter.Create(ms) ) {
		//                se.Body.FirstChild.WriteTo(xw);
		//                xw.Flush();
		//                ms.Position = 0;
		//                sdesc = System.Web.Services.Description.ServiceDescription.Read(ms);
		//            }
		//        }
		//    } catch {
		//        sdesc = null;
		//    }
		//    return sdesc;
		//}
		private XmlSchemaSet createXmlSchemaSet()
		{
			XsdDataContractExporter ex = new XsdDataContractExporter();
			ex.Export(typeof(OpenComposite.EII.Designer.Workflow.Help));
			XmlSchemaSet xsdset = ex.Schemas;
			XmlSchema xsdRemove = null;
			foreach ( XmlSchema xsd in xsdset.Schemas() ) {
				if ( xsd.Elements.Contains(new XmlQualifiedName("Help", xsd.TargetNamespace)) ) {
					xsdRemove = xsd;
				}
			}
			xsdset.Remove(xsdRemove);
			return xsdset;
		}

		#endregion

		#region Event Handlers
		//private void btnOK_Click(object sender, EventArgs e)
		//{
		//    saveClose();
		//}
		private void btnDiscover_Click(object sender, EventArgs e)
		{
			this.Cursor = Cursors.WaitCursor;
			try {
				this.Refresh();
				browseForAPI();
				showInformations();
				this.Cursor = Cursors.Default;
			} catch ( Exception ex ) {
				this.Cursor = Cursors.Default;
				MessageBox.Show(ex.Message, ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error);
			} finally {
				this.Refresh();
			}
		}
		//private void btnShowWSDL_Click(object sender, EventArgs e)
		//{
		//    Repository.WebService ws = this.RepositoryItem as Repository.WebService;
		//    if (ws == null)
		//        throw new Exception("Repository Item is not a webservice.");

		//    if (ws != null) {
		//        formXmlViewer frm = new formXmlViewer();
		//        frm.XmlDocument = ws.WSDL;
		//        frm.ShowDialog();
		//    }
		//}

		private void dgvWebMethods_MouseDown(object sender, MouseEventArgs e)
		{
			System.Windows.Forms.DataGridView.HitTestInfo hti = dgvWebMethods.HitTest(e.X, e.Y);
			if ( hti.RowIndex >= 0 && hti.RowIndex < dgvWebMethods.RowCount ) {
				Repository.WebMethod meth = dgvWebMethods.Rows[hti.RowIndex].DataBoundItem as Repository.WebMethod;
				if ( meth != null ) {
					if ( hti.ColumnIndex == colInputSchema.Index ) {
						showXmlString(meth.InputSchemaString);
					} else if ( hti.ColumnIndex == colOutputSchema.Index ) {
						showXmlString(meth.OutputSchemaString);
					}
				}
			}
		}

		#endregion

		private void dgvWebMethods_DataError(object sender, DataGridViewDataErrorEventArgs e)
		{
			StringBuilder msg = new StringBuilder();
			msg.Append("Column: ").AppendLine(e.ColumnIndex.ToString());
			msg.Append("Context: ").AppendLine(e.Context.ToString());
			msg.Append("Exception: ").AppendLine(e.Exception.Message);
			msg.Append("Row: ").AppendLine(e.RowIndex.ToString());
			MessageBox.Show(msg.ToString(), "Create Service");
		}

	}

}
